#include "adc128s.h"
#include "mymath.h"
#include "zf_delay.h"
#include "zf_spi.h"
#include "zf_gpio.h"
#include "zf_eeprom.h"
#include "zf_adc.h"
#include <stdio.h>

// 要注意的是，Raw采集到的电感通道不太对劲，0是电池，1才到通道0，一直到7是通道6
ADC_type ADC;
// 保存七颗电感的最大最小值
static uint8 xdata tempBuff[28];
// 距离传感器和电池电压滤波缓存
// 这种赋值方法在keil5_C251中不起作用，只会对下标0的元素赋值而不是全体赋值
static fp32 xdata InfVolBuf[10] = {10.0f}, BatVolBuf[10] = {12.6f};
// 缓存指针
static uint8 p, k;

void ADC_Init(void)
{
    uint8 i;
    // 初始化单片机ADC
    zfadc_init(ADC_P13, ADC_SYSclk_DIV_32);
    // 初始化片选引脚
    gpio_mode(P4_5, GPIO);
    ADC_CS_Pin = OFF;
    // 初始化缓存，赋予默认值
    for (i = 0; i < 10; i++)
    {
        InfVolBuf[i] = 5.0f;
        BatVolBuf[i] = 12.6f;
    }
    // 初始化e2prom
    iap_init();
    iap_read_bytes(ROAD_STD_DATA_ADDR, tempBuff, 28);
    // 把缓存的值读取出来
    for (i = 0; i < 28; i += 4)
    {
        ADC.Max[i / 4] = (tempBuff[i] << 8) + tempBuff[i + 1];
        ADC.Min[i / 4] = (tempBuff[i + 2] << 8) + tempBuff[i + 3];
    }
}

void ADC_GetData(void)
{
    uint8 i;
    // 采集原始数据
    for (i = 0; i < 8; i++)
    {
        // 选中外部ADC
        ADC_CS_Pin = ON;
        // 输入要获取的通道，并记录返回的ADC值
        ADC.Raw[i] = spi_mosi(i << 3);
        ADC.Raw[i] <<= 8;
        ADC.Raw[i] += spi_mosi(0x00);
        // 外部ADC关闭
        ADC_CS_Pin = OFF;
    }

    // 获取电池电压
    ADC.BatVol = (zfadc_once(ADC_P13, ADC_8BIT) / 255.0f) * 14.23f; // 33.1k和10k分压
    // 获取红外距离传感器的电压
    ADC.InfVol = ADC.Raw[0] / 4095.0f * 5.0f;
    if (ADC.InfVol < 0.64f || ADC.InfVol > 2.349f)
    { // 0.64 100cm,2.349 20cm
        ADC.InfVol = 10;
    }
    // 更新缓存
    BatVolBuf[p++] = ADC.BatVol;
    if (p >= 10)
        p = 0;
    // 去最大最小值的中值平均滤波
    ADC.BatVol = MidAvg_Filter(BatVolBuf, 10);

    // InfVolBuf[k++] = ADC.InfVol;
    // if (k >= 5)
    //     k = 0;
    // ADC.InfVol = MidAvg_Filter(InfVolBuf, 5);
    // ADC.InfVol = (InfVolBuf[0] + InfVolBuf[1] + InfVolBuf[2] + InfVolBuf[3]) / 6.0f;

    // 归一化
    for (i = 0; i < 7; i++)
    {
        // 归一数据 = （当前值 - 最小值）* 10000 / （最大值 - 最小值）
        ADC.Std[i] = ((fp32)(ADC.Raw[i + 1] - ADC.Min[i]) / (fp32)(ADC.Max[i] - ADC.Min[i])) * 10000.0f;
        // 限幅，得到的是0-10000范围内的数据
        ADC.Std[i] = LIMIT_P(ADC.Std[i], 10000);
    }
}

void ADC_RoadStd()
{
    uint8 i;
    uint16 j;
    // 初始化最大最小值
    for (i = 0; i < 7; i++)
    {
        ADC.Max[i] = 0;
        ADC.Min[i] = 4095;
    }
    // 采集一千次，五秒完成
    for (j = 0; j < 1000; j++)
    {
        delay_ms(5);
        // 采集原始数据
        for (i = 0; i < 8; i++)
        {
            // 选中外部ADC
            ADC_CS_Pin = ON;
            // 输入要获取的通道，并记录返回的ADC值
            ADC.Raw[i] = spi_mosi(i << 3);
            ADC.Raw[i] <<= 8;
            ADC.Raw[i] += spi_mosi(0x00);
            // 外部ADC关闭
            ADC_CS_Pin = OFF;
        }
        // 取最大或最小
        for (i = 0; i < 7; i++)
        {
            if (ADC.Raw[i + 1] > ADC.Max[i])
            {
                ADC.Max[i] = ADC.Raw[i + 1];
            }
            if (ADC.Raw[i + 1] < ADC.Min[i])
            {
                ADC.Min[i] = ADC.Raw[i + 1];
            }
        }
    }
    // 最大最小转换成uint8，以便保存
    for (i = 0; i < 28; i += 4)
    {
        tempBuff[i] = (uint8)(ADC.Max[i / 4] >> 8);
        tempBuff[i + 1] = (uint8)ADC.Max[i / 4];
        tempBuff[i + 2] = (uint8)(ADC.Min[i / 4] >> 8);
        tempBuff[i + 3] = (uint8)ADC.Min[i / 4];
    }
    // 擦除原有的数据
    iap_erase_page(ROAD_STD_DATA_ADDR + 511);
    // 保存赛道数据到e2prom
    iap_write_bytes(ROAD_STD_DATA_ADDR, tempBuff, 28);
}
